using System;
using System.Collections.Generic;
using System.Text;
using MotionBlur.Butler.Model;
using System.Workflow.Runtime;
using System.Collections.ObjectModel;
using System.Threading;

namespace MotionBlur.Butler.Runtime
{

    public class DutyManager
    {

        public event EventHandler<DutyEventArgs> DutyLaunched;

        private WorkflowRuntime _Runtime;
        private List<ITriggerMonitor> _Monitors;
        private Dictionary<Guid, DutyOrder> _RegisteredOrders;
        private Dictionary<Guid, DutyInstance> _RunningInstances;
        
        public DutyManager(ITriggerMonitor[] monitors, WorkflowRuntime runtime)
        {

            _Monitors = new List<ITriggerMonitor>();
            _RegisteredOrders = new Dictionary<Guid, DutyOrder>();
            _RunningInstances = new Dictionary<Guid, DutyInstance>();

            _Monitors.AddRange(monitors);
            _Runtime = runtime;

        }

        public void RegisterOrder(DutyOrder order)
        {

            _RegisteredOrders.Add(order.OrderID, order);

            foreach (DutyTrigger trigger in order.Triggers)
            {

                foreach (ITriggerMonitor monitor in _Monitors)
                {

                    if (monitor.CanRegister(trigger))
                    {

                        TriggerCallback callback = new TriggerCallback(this.HandleTriggerCallback);

                        monitor.RegisterTrigger(trigger, order.OrderID, callback);

                    }

                }

            }

        }

        public void UnregisterOrder(DutyOrder order)
        {

            foreach (DutyTrigger trigger in order.Triggers)
            {

                foreach (ITriggerMonitor monitor in _Monitors)
                {

                    if (monitor.CanRegister(trigger))
                    {

                        monitor.UnregisterTrigger(trigger);

                    }

                }

            }

            _RegisteredOrders.Remove(order.OrderID);
            
        }

        public void StartEngine()
        {

            _RunningInstances.Clear();

            _Runtime.StartRuntime();

            foreach (ITriggerMonitor monitor in _Monitors)
            {
                
                monitor.StartMonitor();

            }

        }

        public void StopEngine()
        {

            foreach (ITriggerMonitor monitor in _Monitors)
            {

                monitor.StopMonitor();

            }

            _Runtime.StopRuntime();

            _RunningInstances.Clear();

        }

        private void HandleTriggerCallback(Guid orderID, Dictionary<string, object> triggerParameters)
        {

            DutyOrder order = _RegisteredOrders[orderID];

            Dictionary<string, object> fullParameters = new Dictionary<string, object>();

            foreach (string triggerParameterKey in triggerParameters.Keys)
            {
                fullParameters.Add(triggerParameterKey, triggerParameters[triggerParameterKey]);
            }

            foreach (string staticParameterKey in order.Parameters.Keys)
            {
                fullParameters.Add(staticParameterKey, order.Parameters[staticParameterKey]);
            }

            WorkflowInstance workflowInstance = _Runtime.CreateWorkflow(order.Workflow, fullParameters);

            DutyInstance dutyInstance = new DutyInstance();

            _RunningInstances.Add(orderID, dutyInstance);

            dutyInstance.Order = order;
            dutyInstance.StartStamp = DateTime.Now;
            dutyInstance.WorkflowInstanceID = workflowInstance.InstanceId;

            workflowInstance.Start();

            DutyEventArgs args = new DutyEventArgs(dutyInstance);

            this.OnDutyLaunched(args);

        }

        private void OnDutyLaunched(DutyEventArgs e)
        {
            if (this.DutyLaunched != null)
            {
                this.DutyLaunched(this, e);
            }
        }

    }

}
